from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from sqlalchemy import func, desc
from typing import List, Optional
from datetime import datetime, timedelta
from backend.database import get_db
from backend.models import Device, Backup, BackupStatus, ScheduleLog
from backend.schemas import (
    DeviceCreate, DeviceUpdate, DeviceResponse,
    BackupResponse, BackupWithDevice,
    ScheduleLogResponse, Statistics
)
from backend.backup_service import BackupService
from backend.cleanup_service import CleanupService
from backend.system_info import SystemInfoService
from backend.config import settings

router = APIRouter()

# ==================== 设备管理 ====================

@router.get("/devices", response_model=List[DeviceResponse])
def get_devices(
    skip: int = 0,
    limit: int = 100,
    is_active: Optional[bool] = None,
    db: Session = Depends(get_db)
):
    """获取设备列表"""
    query = db.query(Device)
    if is_active is not None:
        query = query.filter(Device.is_active == is_active)
    devices = query.offset(skip).limit(limit).all()
    return devices

@router.get("/devices/{device_id}", response_model=DeviceResponse)
def get_device(device_id: int, db: Session = Depends(get_db)):
    """获取单个设备详情"""
    device = db.query(Device).filter(Device.id == device_id).first()
    if not device:
        raise HTTPException(status_code=404, detail="设备不存在")
    return device

@router.post("/devices", response_model=DeviceResponse)
def create_device(device: DeviceCreate, db: Session = Depends(get_db)):
    """创建新设备"""
    # 检查设备名是否已存在
    existing = db.query(Device).filter(Device.name == device.name).first()
    if existing:
        raise HTTPException(status_code=400, detail="设备名已存在")
    
    db_device = Device(**device.model_dump())
    db.add(db_device)
    db.commit()
    db.refresh(db_device)
    return db_device

@router.put("/devices/{device_id}", response_model=DeviceResponse)
def update_device(
    device_id: int,
    device: DeviceUpdate,
    db: Session = Depends(get_db)
):
    """更新设备信息"""
    db_device = db.query(Device).filter(Device.id == device_id).first()
    if not db_device:
        raise HTTPException(status_code=404, detail="设备不存在")
    
    # 更新字段
    update_data = device.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        setattr(db_device, field, value)
    
    db_device.updated_at = datetime.utcnow()
    db.commit()
    db.refresh(db_device)
    return db_device

@router.delete("/devices/{device_id}")
def delete_device(device_id: int, db: Session = Depends(get_db)):
    """删除设备"""
    device = db.query(Device).filter(Device.id == device_id).first()
    if not device:
        raise HTTPException(status_code=404, detail="设备不存在")
    
    db.delete(device)
    db.commit()
    return {"message": "设备已删除"}

# ==================== 备份管理 ====================

@router.post("/devices/{device_id}/backup")
def trigger_backup(device_id: int, db: Session = Depends(get_db)):
    """手动触发设备备份"""
    device = db.query(Device).filter(Device.id == device_id).first()
    if not device:
        raise HTTPException(status_code=404, detail="设备不存在")
    
    try:
        backup_service = BackupService(db)
        backup = backup_service.backup_device(device_id, is_manual=True)
        return {
            "message": "备份成功",
            "backup_id": backup.id,
            "filename": backup.filename
        }
    except Exception as e:
        error_msg = str(e)
        if "TCP connection to device failed" in error_msg:
            raise HTTPException(status_code=400, detail="设备连接失败，请检查IP地址和网络连接")
        elif "Authentication failed" in error_msg:
            raise HTTPException(status_code=400, detail="设备认证失败，请检查用户名和密码")
        else:
            raise HTTPException(status_code=500, detail=f"备份失败: {error_msg}")

@router.get("/backups", response_model=List[BackupWithDevice])
def get_backups(
    skip: int = 0,
    limit: int = 100,
    device_id: Optional[int] = None,
    status: Optional[str] = None,
    db: Session = Depends(get_db)
):
    """获取备份列表"""
    query = db.query(Backup)
    
    if device_id:
        query = query.filter(Backup.device_id == device_id)
    if status:
        query = query.filter(Backup.status == status)
    
    backups = query.order_by(desc(Backup.backup_time)).offset(skip).limit(limit).all()
    return backups

@router.get("/backups/{backup_id}", response_model=BackupResponse)
def get_backup(backup_id: int, db: Session = Depends(get_db)):
    """获取备份详情"""
    backup = db.query(Backup).filter(Backup.id == backup_id).first()
    if not backup:
        raise HTTPException(status_code=404, detail="备份不存在")
    return backup

@router.get("/backups/{backup_id}/content")
def get_backup_content(backup_id: int, db: Session = Depends(get_db)):
    """获取备份配置内容"""
    try:
        backup_service = BackupService(db)
        content = backup_service.get_config_content(backup_id)
        return {"content": content}
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except FileNotFoundError as e:
        raise HTTPException(status_code=404, detail=str(e))

@router.get("/backups/compare/{backup_id1}/{backup_id2}")
def compare_backups(
    backup_id1: int,
    backup_id2: int,
    db: Session = Depends(get_db)
):
    """比较两个备份的差异"""
    try:
        backup_service = BackupService(db)
        result = backup_service.compare_configs(backup_id1, backup_id2)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.delete("/backups/{backup_id}")
def delete_backup(backup_id: int, db: Session = Depends(get_db)):
    """删除备份"""
    backup = db.query(Backup).filter(Backup.id == backup_id).first()
    if not backup:
        raise HTTPException(status_code=404, detail="备份不存在")
    
    # 删除文件
    import os
    if os.path.exists(backup.filepath):
        os.remove(backup.filepath)
    
    db.delete(backup)
    db.commit()
    return {"message": "备份已删除"}

# ==================== 统计信息 ====================

@router.get("/statistics", response_model=Statistics)
def get_statistics(db: Session = Depends(get_db)):
    """获取统计信息"""
    total_devices = db.query(Device).count()
    active_devices = db.query(Device).filter(Device.is_active == True).count()
    total_backups = db.query(Backup).count()
    
    # 今天的备份数
    today_start = datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0)
    today_backups = db.query(Backup).filter(Backup.backup_time >= today_start).count()
    
    # 成功率
    success_backups = db.query(Backup).filter(Backup.status == BackupStatus.SUCCESS).count()
    success_rate = (success_backups / total_backups * 100) if total_backups > 0 else 0
    
    # 总备份大小
    total_size = db.query(func.sum(Backup.file_size)).scalar() or 0
    
    return {
        "total_devices": total_devices,
        "active_devices": active_devices,
        "total_backups": total_backups,
        "today_backups": today_backups,
        "success_rate": round(success_rate, 2),
        "total_backup_size": total_size
    }

# ==================== 调度日志 ====================

@router.get("/schedule-logs", response_model=List[ScheduleLogResponse])
def get_schedule_logs(
    skip: int = 0,
    limit: int = 50,
    db: Session = Depends(get_db)
):
    """获取调度日志"""
    logs = db.query(ScheduleLog).order_by(desc(ScheduleLog.execute_time)).offset(skip).limit(limit).all()
    return logs

# ==================== 设备连接测试 ====================

@router.post("/devices/{device_id}/test")
def test_device_connection(device_id: int, db: Session = Depends(get_db)):
    """测试设备连接"""
    device = db.query(Device).filter(Device.id == device_id).first()
    if not device:
        raise HTTPException(status_code=404, detail="设备不存在")

    try:
        import socket
        from netmiko import ConnectHandler

        # 第一步：测试网络连通性
        try:
            socket.setdefaulttimeout(5)
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            result = sock.connect_ex((device.ip_address, device.port))
            sock.close()

            if result != 0:
                return {
                    "success": False,
                    "message": f"网络连接失败：无法连接到 {device.ip_address}:{device.port}。请检查：\n1. IP地址是否正确\n2. 端口是否正确\n3. 网络是否可达\n4. 防火墙是否阻挡"
                }
        except Exception as e:
            return {
                "success": False,
                "message": f"网络测试失败: {str(e)}"
            }

        # 第二步：测试SSH连接和命令支持
        try:
            # 映射设备类型到Netmiko支持的设备类型
            device_type_mapping = {
                'huawei_rsr77': 'huawei_vrp',
                'huawei_ar2220': 'huawei_vrp',
                'huawei_vrp': 'huawei_vrp',
                'huawei': 'huawei',
                'cisco_ios': 'cisco_ios',
                'cisco_xe': 'cisco_xe',
                'cisco_asa': 'cisco_asa',
                'h3c': 'hp_comware',
                'juniper': 'juniper',
                'arista_eos': 'arista_eos'
            }
            
            mapped_device_type = device_type_mapping.get(device.device_type, device.device_type)
            
            device_params = {
                'device_type': mapped_device_type,
                'host': device.ip_address,
                'username': device.username,
                'password': device.password,
                'port': device.port,
                'timeout': 10,
                'session_log': None,
            }

            if device.enable_password:
                device_params['secret'] = device.enable_password

            connection = ConnectHandler(**device_params)
            prompt = connection.find_prompt()
            
            # 第三步：测试配置命令支持
            backup_service = BackupService(db)
            try:
                config = backup_service.get_device_config(device)
                connection.disconnect()
                return {
                    "success": True,
                    "message": f"连接成功！\n设备类型: {device.device_type}\n设备提示符: {prompt}\nIP地址: {device.ip_address}:{device.port}\n配置获取: 成功\n配置长度: {len(config)} 字符"
                }
            except Exception as config_error:
                connection.disconnect()
                error_msg = str(config_error)
                
                # 提供更详细的错误分析和建议
                suggestions = []
                if "unknown command" in error_msg.lower() or "% unknown" in error_msg.lower():
                    suggestions.append("设备不支持该命令，请尝试其他设备类型")
                if "permission denied" in error_msg.lower() or "denied" in error_msg.lower():
                    suggestions.append("用户权限不足，请检查用户名密码或用户权限")
                if "timeout" in error_msg.lower():
                    suggestions.append("命令执行超时，请检查网络连接或设备响应")
                if "empty" in error_msg.lower() or "空结果" in error_msg:
                    suggestions.append("命令返回空结果，可能是设备不支持或权限不足")
                
                if not suggestions:
                    suggestions = [
                        "检查设备类型是否正确",
                        "确认用户权限是否足够", 
                        "尝试其他设备类型",
                        "检查设备是否支持SSH配置备份"
                    ]
                
                suggestion_text = "\n".join([f"{i+1}. {s}" for i, s in enumerate(suggestions)])
                
                return {
                    "success": False,
                    "message": f"SSH连接成功，但配置获取失败：\n\n{error_msg}\n\n建议：\n{suggestion_text}"
                }
                
        except Exception as e:
            error_msg = str(e)
            if "Authentication failed" in error_msg:
                return {
                    "success": False,
                    "message": f"认证失败：用户名或密码错误。请检查：\n1. 用户名是否正确\n2. 密码是否正确\n3. 用户是否有SSH权限"
                }
            elif "Connection refused" in error_msg:
                return {
                    "success": False,
                    "message": f"连接被拒绝：SSH服务可能未启用。请检查：\n1. 设备是否启用SSH服务\n2. SSH端口是否正确\n3. 设备是否允许SSH连接"
                }
            elif "timeout" in error_msg.lower():
                return {
                    "success": False,
                    "message": f"连接超时：设备响应超时。请检查：\n1. 网络延迟是否过高\n2. 设备是否繁忙\n3. 防火墙是否阻挡"
                }
            else:
                return {
                    "success": False,
                    "message": f"SSH连接失败: {error_msg}\n\n建议检查：\n1. 设备类型是否正确\n2. SSH服务是否启用\n3. 用户名密码是否正确\n4. 网络连接是否正常"
                }
    except Exception as e:
        return {
            "success": False,
            "message": f"测试失败: {str(e)}"
        }

# ==================== 系统设置 ====================

@router.get("/settings")
def get_settings():
    """获取系统设置"""
    return {
        "backup_interval_hours": settings.BACKUP_INTERVAL_HOURS,
        "backup_dir": settings.BACKUP_DIR
    }

@router.get("/device-types")
def get_device_types():
    """获取支持的设备类型列表"""
    return {
        "device_types": [
            {
                "value": "cisco_ios",
                "label": "Cisco IOS",
                "description": "Cisco IOS 设备 (show running-config)",
                "commands": ["show running-config", "show run", "show config", "show running-config all", "show startup-config"]
            },
            {
                "value": "huawei",
                "label": "华为 (Huawei)",
                "description": "华为 VRP 系统设备 (display current-configuration)",
                "commands": ["display current-configuration", "display current-config", "display saved-configuration", "display current-configuration all", "show running-config", "show config"]
            },
            {
                "value": "huawei_vrp",
                "label": "华为 VRP",
                "description": "华为 VRP 系统 (支持 show 和 display 命令)",
                "commands": ["show running-config", "show config", "display current-configuration", "show version", "show interfaces"]
            },
            {
                "value": "huawei_ar2220",
                "label": "华为 AR2220",
                "description": "华为 AR2220 路由器 (VRP 5.130, 支持 display 命令)",
                "commands": ["display current-configuration", "display current-config", "display saved-configuration", "display version", "display interfaces", "display ip routing-table"]
            },
            {
                "value": "h3c",
                "label": "H3C (Comware)",
                "description": "H3C Comware 系统设备 (display current-configuration)",
                "commands": ["display current-configuration", "display current-config", "display saved-configuration", "display current-configuration all"]
            },
            {
                "value": "juniper_junos",
                "label": "Juniper JunOS",
                "description": "Juniper JunOS 设备 (show configuration)",
                "commands": ["show configuration", "show config", "show running-config", "show configuration | display set"]
            },
            {
                "value": "arista_eos",
                "label": "Arista EOS",
                "description": "Arista EOS 设备 (show running-config)",
                "commands": ["show running-config", "show run", "show config", "show running-config all"]
            },
            {
                "value": "generic",
                "label": "通用设备",
                "description": "尝试多种命令的通用设备",
                "commands": ["show running-config", "display current-configuration", "show configuration", "show config", "show run"]
            }
        ]
    }

@router.post("/devices/{device_id}/debug")
def debug_device_commands(device_id: int, db: Session = Depends(get_db)):
    """调试设备命令执行过程"""
    device = db.query(Device).filter(Device.id == device_id).first()
    if not device:
        raise HTTPException(status_code=404, detail="设备不存在")

    try:
        from netmiko import ConnectHandler
        import logging
        
        # 设置详细日志
        logging.basicConfig(level=logging.DEBUG)
        
        # 映射设备类型到Netmiko支持的设备类型
        device_type_mapping = {
            'huawei_rsr77': 'huawei_vrp',
            'huawei_ar2220': 'huawei_vrp',
            'huawei_vrp': 'huawei_vrp',
            'huawei': 'huawei',
            'cisco_ios': 'cisco_ios',
            'cisco_xe': 'cisco_xe',
            'cisco_asa': 'cisco_asa',
            'h3c': 'hp_comware',
            'juniper': 'juniper',
            'arista_eos': 'arista_eos'
        }
        
        mapped_device_type = device_type_mapping.get(device.device_type, device.device_type)
        
        device_params = {
            'device_type': mapped_device_type,
            'host': device.ip_address,
            'username': device.username,
            'password': device.password,
            'port': device.port,
            'timeout': 30,
            'session_log': None,
        }
        
        if device.enable_password:
            device_params['secret'] = device.enable_password

        connection = ConnectHandler(**device_params)
        prompt = connection.find_prompt()
        
        # 获取设备类型对应的命令列表，包括更多华为设备命令
        device_type_lower = device.device_type.lower()
        if 'cisco' in device_type_lower or 'ios' in device_type_lower:
            commands = ['show running-config', 'show run', 'show config', 'show running-config all', 'show startup-config']
        elif 'huawei' in device_type_lower or 'vrp' in device_type_lower:
            commands = [
                'display current-configuration', 'display current-config', 'display saved-configuration', 
                'display current-configuration all', 'display startup-configuration', 'display config current',
                'display running-config', 'show running-config', 'show config', 'display configuration',
                'display config', 'show current-configuration', 'display startup-config', 'show startup-configuration',
                'show version', 'show clock', 'show users', 'show interfaces', 'show ip route', 'show vlan'
            ]
        elif 'h3c' in device_type_lower or 'comware' in device_type_lower:
            commands = ['display current-configuration', 'display current-config', 'display saved-configuration', 'display current-configuration all']
        elif 'juniper' in device_type_lower or 'junos' in device_type_lower:
            commands = ['show configuration', 'show config', 'show running-config', 'show configuration | display set']
        elif 'arista' in device_type_lower or 'eos' in device_type_lower:
            commands = ['show running-config', 'show run', 'show config', 'show running-config all']
        else:
            commands = ['show running-config', 'display current-configuration', 'show configuration', 'show config', 'show run']
        
        # 特殊华为设备处理
        if 'HBGC' in prompt or 'RSR77' in prompt:
            commands.extend([
                'show running-config', 'show config', 'show configuration', 'show current-configuration',
                'show startup-configuration', 'show version', 'show clock', 'show users', 'show interfaces',
                'show ip route', 'show vlan', 'show arp', 'show mac-address-table'
            ])
        
        results = []
        for i, command in enumerate(commands):
            try:
                result = connection.send_command(command, delay_factor=2)
                
                # 安全处理编码问题 - 处理可能的Unicode字符
                if result:
                    try:
                        # 确保结果是字符串类型
                        if not isinstance(result, str):
                            result = str(result)
                        
                        # 处理可能的编码问题
                        if isinstance(result, bytes):
                            result = result.decode('utf-8', errors='replace')
                        else:
                            # 对于已经是字符串的情况，确保能安全处理Unicode字符
                            result = result.encode('utf-8', errors='replace').decode('utf-8')
                    except (UnicodeEncodeError, UnicodeDecodeError, AttributeError):
                        # 如果所有编码处理都失败，使用最基本的转换
                        result = str(result)
                results.append({
                    "command": command,
                    "success": True,
                    "result_length": len(result) if result else 0,
                    "result_preview": result[:200] + "..." if result and len(result) > 200 else result,
                    "has_errors": any(error in result.lower() if result else "" for error in [
                        'unknown command', 'invalid command', 'command not found', '% unknown', '% invalid'
                    ])
                })
            except Exception as e:
                results.append({
                    "command": command,
                    "success": False,
                    "error": str(e),
                    "result_length": 0,
                    "result_preview": None,
                    "has_errors": True
                })
        
        connection.disconnect()
        
        return {
            "device": {
                "name": device.name,
                "ip_address": device.ip_address,
                "device_type": device.device_type,
                "prompt": prompt
            },
            "commands_tested": len(commands),
            "results": results,
            "summary": {
                "successful_commands": len([r for r in results if r["success"] and not r["has_errors"]]),
                "failed_commands": len([r for r in results if not r["success"] or r["has_errors"]]),
                "best_command": next((r for r in results if r["success"] and not r["has_errors"] and r["result_length"] > 100), None)
            }
        }
        
    except Exception as e:
        return {
            "error": f"调试失败: {str(e)}",
            "device": {
                "name": device.name,
                "ip_address": device.ip_address,
                "device_type": device.device_type
            }
        }

@router.post("/settings/backup-interval")
def update_backup_interval(hours: int):
    """更新备份间隔时间"""
    if hours < 1 or hours > 168:  # 1小时到7天
        raise HTTPException(status_code=400, detail="备份间隔必须在1-168小时之间")
    
    # 更新全局设置
    settings.BACKUP_INTERVAL_HOURS = hours
    
    # 重启调度器
    from backend.scheduler import backup_scheduler
    backup_scheduler.restart_backup_job(hours)
    
    return {
        "message": f"备份间隔已更新为 {hours} 小时",
        "backup_interval_hours": hours
    }

@router.post("/backup/trigger-all")
def trigger_all_backup(db: Session = Depends(get_db)):
    """手动触发所有设备备份"""
    from backend.scheduler import backup_scheduler
    import threading
    
    # 在后台线程执行，避免阻塞
    thread = threading.Thread(target=backup_scheduler.auto_backup_all_devices)
    thread.start()
    
    return {"message": "已触发全部设备备份，请查看调度日志"}

# ==================== 备份清理 ====================

@router.post("/backup/cleanup")
def cleanup_old_backups(db: Session = Depends(get_db)):
    """手动清理旧备份"""
    try:
        cleanup_service = CleanupService(db)
        result = cleanup_service.cleanup_old_backups()
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.post("/backup/cleanup/{device_id}")
def cleanup_device_backups(device_id: int, db: Session = Depends(get_db)):
    """清理指定设备的旧备份"""
    try:
        cleanup_service = CleanupService(db)
        result = cleanup_service.cleanup_device_backups(device_id)
        return result
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/backup/stats")
def get_backup_stats(db: Session = Depends(get_db)):
    """获取备份统计信息"""
    try:
        cleanup_service = CleanupService(db)
        stats = cleanup_service.get_backup_stats()
        return stats
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.put("/backup/cleanup/max-backups")
def update_max_backups(max_backups: int, db: Session = Depends(get_db)):
    """更新每个设备最大保留备份数量"""
    try:
        if max_backups < 1 or max_backups > 50:
            raise HTTPException(status_code=400, detail="备份保留数量必须在1-50之间")
        
        cleanup_service = CleanupService(db)
        cleanup_service.set_max_backups(max_backups)
        
        return {
            "success": True,
            "max_backups": max_backups,
            "message": f"已更新每个设备最大保留备份数量为 {max_backups} 个"
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/backup/cleanup/config")
def get_cleanup_config():
    """获取清理配置"""
    from backend.cleanup_service import CleanupService
    cleanup_service = CleanupService(None)  # 不需要数据库连接
    return {
        "max_backups_per_device": cleanup_service.max_backups_per_device
    }

# ==================== 系统信息 ====================

@router.get("/system/info")
def get_system_info():
    """获取系统信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_all_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/system/basic")
def get_system_basic():
    """获取系统基本信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_system_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/system/cpu")
def get_system_cpu():
    """获取CPU信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_cpu_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/system/memory")
def get_system_memory():
    """获取内存信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_memory_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/system/disk")
def get_system_disk():
    """获取磁盘信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_disk_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@router.get("/system/network")
def get_system_network():
    """获取网络信息"""
    try:
        system_service = SystemInfoService()
        return system_service.get_network_info()
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
